package com.coscon.filter;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 拦截防止xss注入
 * 通过Jsoup过滤请求参数内的特定字符
 * @author 409390047@qq.com
 */
@Slf4j
public class XssFilter implements Filter {

	private  boolean isIncludeRichTextFlag = false;//是否过滤富文本内容

	public List<String> excludes = new ArrayList<String>();

	//排除不需要处理的input的name
	public String[] extInputNames = null;

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,ServletException {

		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;

		///////////////////////////////两种做法，1：在nginx上添加，2：自己加(默认)///////////////////////////////////////
		//添加这个处理
		resp.setHeader("x-frame-options","SAMEORIGIN"); //X-Frame-Options
		//处理HttpOnly，主要目的是：js不能对cookie操作，以后如果发现有问题，则注释掉这行,参考：https://www.cnblogs.com/digdeep/p/4695348.html
//		String sessionid = null;
//		HttpSession httpSession = req.getSession();//有可能为null，因为部分api是无状态的
//		if(httpSession!=null){
//			sessionid = httpSession.getId();
//		}
//		if(StringUtils.isNotBlank(sessionid)){
//			resp.setHeader("SET-COOKIE", "JSESSIONID=" + sessionid + "; HttpOnly");
//		}

		//X-XSS-Protection
		resp.setHeader("X-XSS-Protection","1");

		//Content-Security-Policy:只允许同源下的资源,不可设置原因：部分css是谷歌的
//		resp.setHeader("Content-Security-Policy","default-src 'self';");

		if(handleExcludeUrl(req, resp)){
			filterChain.doFilter(request, response);
			return;
		}

		XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);

		if(extInputNames!=null && ArrayUtils.isNotEmpty(extInputNames)){
			xssRequest.setExtInputNames(extInputNames);
		}

		filterChain.doFilter(xssRequest, response);
	}

	private boolean handleExcludeUrl(HttpServletRequest request, HttpServletResponse response) {

		if (excludes == null || excludes.isEmpty()) {
			return false;
		}

		String url = request.getServletPath();
		for (String pattern : excludes) {
			Pattern p = Pattern.compile("^" + pattern);
			Matcher m = p.matcher(url);
			if (m.find()) {
				return true;
			}
		}

		return false;
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		log.info("xss filter init~~~~~~~~~~~~");
		String isIncludeRichText = filterConfig.getInitParameter("isIncludeRichText");
		if(StringUtils.isNotBlank(isIncludeRichText)){
			isIncludeRichTextFlag = BooleanUtils.toBoolean(isIncludeRichText);
		}

		String temp = filterConfig.getInitParameter("excludes");
		if (temp != null) {
			String[] url = temp.split(",");
			for (int i = 0; url != null && i < url.length; i++) {
				excludes.add(url[i]);
			}
		}


		String extInputNamesTemp = filterConfig.getInitParameter("extInputNames");
		log.info("extInputNames_temp=" + extInputNamesTemp);
		if(StringUtils.isNotEmpty(extInputNamesTemp)){
			StringTokenizer st = new StringTokenizer(extInputNamesTemp,",");
			extInputNames = new String[st.countTokens()];
			int i = 0;
			while(st.hasMoreTokens()){
				extInputNames[i] = st.nextToken();
				i++;
			}
		}

	}

	@Override
	public void destroy() {

	}

}
